package tc.jv.task5;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;

import tc.jv.task4.AbstractVector;
import tc.jv.task4.Vector;
import tc.jv.task9.IncompatibleVectorSizeException;

public class JArrayListVector extends AbstractVector implements Cloneable, Iterable<Double>
{

	/**
	 * 
	 */
	private static final long serialVersionUID = 6990809308517638511L;
	
	private ArrayList<Double> data;
	
	// CONSTRUCTORS

	public JArrayListVector()
	{
		data = new ArrayList<Double>();
	}
	
	public JArrayListVector(int size)
	{
		data = new ArrayList<Double>(size);
		while (size-- > 0)
			data.add(0.0);
	}
	
	public JArrayListVector(double ... value)
	{
		data = new ArrayList<Double>();
		for (Double d : value)
			add(d);
	}
	
	// ACCESSORS
	
	@Override
	public int size()
	{
		return data.size();
	}
	
	@Override
	public double get(int index)
	{
		return data.get(index);
	}
	
	@Override
	public double set(int index, double value)
	{
		return data.set(index, value);
	}
	
	// SUPERCLASS METHODS
	
	@SuppressWarnings("unchecked")
	// TODO Clone
	@Override
	public Object clone()
	{
		JArrayListVector v = null;
		v = (JArrayListVector) super.clone();
		v.data = (ArrayList<Double>) this.data.clone();
		return v;
	}

	@Override
	public boolean equals(Object obj)
	{
		if (obj == this)
			return true;
		if (obj instanceof JArrayListVector)
		{
			JArrayListVector v = (JArrayListVector) obj;
			return data.size() == v.data.size() ? data.equals(v.data) : false;
		}
		else if (obj instanceof Vector)
		{
			Vector v = (Vector) obj;
			if (this.data.size() == v.size())
			{	
				boolean e = true;
	
				for (int i = 0; e == true && i < this.data.size(); i++)
					e &= (data.get(i) == v.get(i));
				
				return e;
			}				
			else
				return false;
		}
			return false;
	}

	@Override
	public int hashCode()
	{
		long lhc = 0;
		
		for (Double d : data)
			lhc ^= (long) d.doubleValue();
		
		int hc = (int) (lhc >> 32) ^ (int) lhc;
		
		return hc;		
	}

	@Override
	public String toString()
	{
		String format = "%f\t";
		return formAString(format);
	}

	// METHODS
	
	public String toString(int pcs)
	{
		String format = String.format("%%.%df\t", pcs); // %.<precision>f
		return formAString(format);
	}
	
	protected String formAString(String format)
	{
		String s = "";
		for (Double d : data)
			s = s + String.format(Locale.US, format, d);
		return s;
	}

	@Override
	public void print()
	{		
		System.out.println(toString());
	}

	@Override
	public void print(int pcs)
	{		
		System.out.println(toString(pcs));
	}
	
	public void addFirst(double value)
	{
		data.add(0, value);
	}
	
	public void addLast(double value)
	{
		this.add(value);
	}
	
	public void add(double value)
	{
		data.add(value);
	}
	
	@Override
	public boolean add(int index, double value) {
		data.add(index, value);
		return true;
	}

	public double remove(int index)
	{
		return data.remove(index);
	}
	
	@Override
	public boolean fill(double[] array) throws IncompatibleVectorSizeException
	{
		return fill(array, 0);
	}
	
	@Override
	public boolean fill(double[] array, int position) throws IncompatibleVectorSizeException
	{
		vectorArgumentCheck(array, position);
		
		for (int i = 0; i < array.length; i++)
			data.set(i+position, array[i]);
		
		return true;
	}
	
	@Override
	public boolean fill(Vector v) throws IncompatibleVectorSizeException
	{
		return fill(v, 0);
	}
	
	@Override
	public boolean fill(Vector v, int position) throws IncompatibleVectorSizeException
	{
		vectorArgumentCheck(v, position);
		
		for (int i = 0; i < v.size(); i++)
			data.set(position+i, v.get(i));
		
		return true;
	}

	@Override
	public boolean sum(Vector v) throws IncompatibleVectorSizeException
	{
		return sum(v, 0);
	}
	
	@Override
	public boolean sum(Vector v, int position) throws IncompatibleVectorSizeException
	{
		vectorArgumentCheck(v, position);
		
		for (int i = 0; i < v.size(); i++)
			data.set(position+i, data.get(position+i) + v.get(i));

		return true;
	}
	
	@Override
	public boolean multiply(double multiplicator)
	{
		multiplicatorCheck(multiplicator);
		
		for (int i = 0; i < data.size(); i++)
			data.set(i, data.get(i) * multiplicator);

		return true;
	}

		@Override
	public Iterator<Double> iterator()
	{
		return data.iterator();
	}

}
